package service

import (
	"fmt"
	"os"
	"os/signal"
	"sort"
	"sync"
	"syscall"

	"gitee.com/cjianwen/go/logs"
)

type IModule interface {
	GetName() string
	GetModuleId() int // 获取初始化顺序，值越小越在前面先初始化
	Init() error
	Run() error
	Final() error
}

/*
所有模块的基类，初始化时要设置名字和模块ID

其它方法可以不实现，但一定要实现 IModule.Run 方法

demo:

	type myModule struct{
		*service.Module
	}

	func (m *myModule) Run() error{
		return nil
	}

	// 包的初始化函数中注册模块
	func Init(){
		md := &service.Module{Name: "myModule", 1}
		service.RegisterModule(&myModule(Module: md))
	}

	//下面是 Module 实现的几个基础函数，没用到的可以不重写
*/
type Module struct {
	Name     string // 模块名称，出错显示用
	ModuleId int    // 获取初始化顺序，值越小越在前面先初始化
}

// 模块名称，出错显示用
func (m *Module) GetName() string {
	return m.Name
}

// 获取初始化顺序，值越小越在前面先初始化
func (m *Module) GetModuleId() int {
	return m.ModuleId
}

func (m *Module) Init() error {
	return nil
}

func (m *Module) Final() error {
	return nil
}

type service struct {
	modules  []IModule
	isRun    bool
	stopChan chan int
}

var instance *service
var once sync.Once

func getInstance() *service {
	once.Do(func() {
		instance = &service{}
	})
	return instance
}

func (s *service) init() error {
	// 先排序，再使用，按照顺序初始化
	sort.Slice(s.modules, func(i, j int) bool {
		return s.modules[i].GetModuleId() < s.modules[j].GetModuleId()
	})

	var err error
	for _, m := range s.modules {
		err = m.Init()
		if err != nil {
			return fmt.Errorf("%s init error: %s", m.GetName(), err)
		}
	}
	return nil
}

func (s *service) run() {
	var err error
	for _, v := range s.modules {
		err = v.Run()
		if err != nil {
			logs.Println("run error: ", v.GetName(), err)
		}
	}
}

func (s *service) final() {
	for i := len(s.modules) - 1; i >= 0; i-- {
		m := s.modules[i]
		err := m.Final()
		if err != nil {
			logs.Println("run error: ", m.GetName(), err)
		}
	}
}

func (s *service) start() {
	s.stopChan = make(chan int, 1)
	s.isRun = true
	go func() {
		defer func() {
			if r := recover(); r != nil {
				logs.Warn("service.start service error: %s", r)
			}
		}()

		s.init()
		for s.isRun {
			s.run()
		}
		s.final()
		logs.Println("service go routine stoped")
		s.stopChan <- 1
	}()
}

func (s *service) stop() {
	s.isRun = false
	<-s.stopChan
	logs.Println("stop ok")
}

func (s *service) registerService(md IModule) {
	fmt.Println("service.RegisterService: ", md.GetName())
	s.modules = append(s.modules, md)
}

func RegisterModule(module IModule) {
	getInstance().registerService(module)
}

func Start() {

	defer func() {
		if r := recover(); r != nil {
			logs.Warn("Start service error: %s", r)
		}
	}()

	// 定义一个退出信号通道
	stopChan := make(chan os.Signal, 1)
	// 监听中断信号
	signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM)

	getInstance().start()

	<-stopChan

	logs.Println("开始优雅地关闭")

	getInstance().stop()

	logs.Println("优雅关闭完成")

	// time.Sleep(time.Second)
}
